﻿#pragma once

#include <zlib.h>

namespace Util
{
  void Compress(std::vector<uint8_t> &data, std::vector<uint8_t> &compressedData)
  {
    // 使用zlib进行压缩
    z_stream c_stream; // z_stream是zlib库中用于压缩和解压缩的结构体
    c_stream.zalloc = Z_NULL; // 分配内存的函数，这里使用默认的NULL
    c_stream.zfree = Z_NULL; // 释放内存的函数，这里使用默认的NULL
    c_stream.opaque = Z_NULL; // 用于传递额外参数的指针，这里使用默认的NULL
    c_stream.avail_in = data.size(); // 输入数据的大小
    c_stream.next_in = data.data(); // 输入数据的指针
    c_stream.avail_out = 0; // 输出数据的大小，这里初始化为0
    c_stream.next_out = Z_NULL; // 输出数据的指针，这里使用默认的NULL

    if (deflateInit(&c_stream, Z_BEST_COMPRESSION) != Z_OK) // 初始化压缩流，这里使用Z_BEST_COMPRESSION表示使用最高压缩级别
    {
      throw std::runtime_error("Failed to initialize compression stream"); // 如果初始化失败，抛出异常
    }

    // 分配一个足够大的缓冲区来存储压缩后的数据
    compressedData.resize(data.size()); // 这里使用原数据大小作为缓冲区的大小

    c_stream.avail_out = compressedData.size(); // 设置输出数据的大小
    c_stream.next_out = compressedData.data(); // 设置输出数据的指针

    // 执行压缩操作，直到所有输入数据都被处理
    while (c_stream.avail_in != 0) // 如果还有输入数据未处理
    {
      if (deflate(&c_stream, Z_FINISH) == Z_STREAM_ERROR) // 执行压缩操作，如果发生错误
      {
        throw std::runtime_error("Failed to compress data"); // 抛出异常
      }
    }

    // 计算压缩后的数据的大小
    size_t compressedSize = compressedData.size() - c_stream.avail_out; // 计算压缩后的数据的大小
    compressedData.resize(compressedSize); // 调整缓冲区的大小，只保留实际使用的部分

    // 清理压缩流
    if (deflateEnd(&c_stream)!= Z_OK) // 清理压缩流，这里使用deflateEnd函数
    {
      throw std::runtime_error("Failed to end compression stream"); // 如果清理失败，抛出异常
    }
  }

  void Decompress(std::vector<uint8_t> &compressedData, uint32_t dataSize, std::vector<uint8_t> &data) 
  {
    // 使用zlib进行解压缩
    z_stream d_stream = {0}; // z_stream是zlib库中用于压缩和解压缩的结构体
    d_stream.zalloc = Z_NULL; // 分配内存的函数，这里使用默认的NULL
    d_stream.zfree = Z_NULL; // 释放内存的函数，这里使用默认的NULL
    d_stream.opaque = Z_NULL; // 用于传递额外参数的指针，这里使用默认的NULL
    d_stream.avail_in = compressedData.size(); // 输入数据的大小
    d_stream.next_in = compressedData.data(); // 输入数据的指针
    d_stream.avail_out = 0; // 输出数据的大小，这里初始化为0
    d_stream.next_out = Z_NULL; // 输出数据的指针，这里使用默认的NULL

    if (inflateInit(&d_stream)!= Z_OK) // 初始化解压缩流，这里使用inflateInit函数
    {
      throw std::runtime_error("Failed to initialize decompression stream"); // 如果初始化失败，抛出异常
    }

    data.resize(dataSize);

    d_stream.avail_out = data.size(); // 设置输出数据的大小
    d_stream.next_out = data.data(); // 设置输出数据的指针

    int ret;
    do
    {
      ret = inflate(&d_stream, Z_NO_FLUSH);
      if (ret != Z_OK && ret != Z_STREAM_END)
      {
        throw std::runtime_error("Failed to decompress data");
      }
    } while (ret != Z_STREAM_END && d_stream.avail_out > 0);

    // 计算解压缩后的数据的大小
    size_t decompressedSize = data.size() - d_stream.avail_out; // 计算解压缩后的数据的大小
    data.resize(decompressedSize); // 调整缓冲区的大小，只保留实际使用的部分

    // 清理解压缩流
    if (inflateEnd(&d_stream)!= Z_OK) // 清理解压缩流，这里使用inflateEnd函数
    {
      throw std::runtime_error("Failed to end decompression stream"); // 如果清理失败，抛出异常
    }
  }
} // namespace Util
